﻿#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/url.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <string>
#include <map>

namespace beast = boost::beast;         // from <boost/beast.hpp>
namespace http = beast::http;           // from <boost/beast/http.hpp>
namespace net = boost::asio;            // from <boost/asio.hpp>
namespace ssl = net::ssl;               // from <boost/asio/ssl.hpp>
namespace urls = boost::urls;           // from <boost/url.hpp>
using tcp = net::ip::tcp;               // from <boost/asio/ip/tcp.hpp>

class HttpClient {
public:
    struct Response {
        int status_code = 0;
        std::string body;
        std::map<std::string, std::string> headers;
        std::string status_message;

        bool ok() const { return status_code >= 200 && status_code < 300; }
        std::string text() const { return body; }

        // 简单的 JSON 解析支持
        template<typename T>
        T get_json() const {
            T result;
            if (!body.empty()) {
                std::istringstream iss(body);
                boost::property_tree::read_json(iss, result);
            }
            return result;
        }
    };

    struct RequestConfig {
        long connect_timeout = 30;      // 连接超时秒数
        long request_timeout = 60;      // 请求超时秒数
        std::map<std::string, std::string> headers;
        bool follow_redirects = true;
        int max_redirects = 5;
        bool verify_ssl = true;
    };

private:
    net::io_context ioc_;
    RequestConfig config_;

public:
    explicit HttpClient(const RequestConfig& config = RequestConfig())
        : config_(config) {}

    // 同步 GET 请求
    Response get(const std::string& url) {
        return request(http::verb::get, url, "");
    }

    // 同步 POST 请求
    Response post(const std::string& url, const std::string& data = "",
                  const std::string& content_type = "application/json") {
        auto config = config_;
        config.headers["Content-Type"] = content_type;
        return request(http::verb::post, url, data, config);
    }

    // 同步 PUT 请求
    Response put(const std::string& url, const std::string& data = "",
                 const std::string& content_type = "application/json") {
        auto config = config_;
        config.headers["Content-Type"] = content_type;
        return request(http::verb::put, url, data, config);
    }

    // 同步 DELETE 请求
    Response del(const std::string& url) {
        return request(http::verb::delete_, url, "");
    }

    // 通用请求方法
    Response request(http::verb method, const std::string& url,
                    const std::string& body = "",
                    const RequestConfig& config = RequestConfig{}) {
        urls::url parsed_url;
        try {
            parsed_url = urls::url_view(url);
        } catch (const std::exception& e) {
            return make_error_response(400, "Invalid URL: " + std::string(e.what()));
        }

        std::string scheme = parsed_url.scheme();
        std::string host = parsed_url.host();
        std::string port = parsed_url.port();
        std::string target = parsed_url.path();

        if (target.empty()) target = "/";
        if (!parsed_url.query().empty()) {
            target += "?" + std::string(parsed_url.query());
        }

        if (port.empty()) {
            port = (scheme == "https") ? "443" : "80";
        }

        try {
            if (scheme == "https") {
                return https_request(method, host, port, target, body, config);
            } else {
                return http_request(method, host, port, target, body, config);
            }
        } catch (const std::exception& e) {
            return make_error_response(500, "Network error: " + std::string(e.what()));
        }
    }

    // 设置默认配置
    void set_default_config(const RequestConfig& config) {
        config_ = config;
    }

private:
    Response http_request(http::verb method,
                         const std::string& host,
                         const std::string& port,
                         const std::string& target,
                         const std::string& body,
                         const RequestConfig& config) {

        tcp::resolver resolver(ioc_);
        beast::tcp_stream stream(ioc_);

        // 设置连接超时
        // Note: Boost.Beast 在同步模式下不直接支持超时，需要使用异步或系统级超时

        // 解析地址
        auto const results = resolver.resolve(host, port);

        // 连接
        stream.connect(results);

        // 创建请求
        http::request<http::string_body> req{method, target, 11};
        req.set(http::field::host, host);
        req.set(http::field::user_agent, "HttpClient/1.0");

        // 设置请求头
        for (const auto& header : config.headers) {
            req.set(header.first, header.second);
        }

        // 设置请求体
        if (!body.empty()) {
            req.body() = body;
            req.prepare_payload();
        }

        // 发送请求
        http::write(stream, req);

        // 接收响应
        beast::flat_buffer buffer;
        http::response<http::dynamic_body> res;
        http::read(stream, buffer, res);

        // 关闭连接
        beast::error_code ec;
        stream.socket().shutdown(tcp::socket::shutdown_both, ec);

        // 处理响应
        return parse_response(res);
    }

    Response https_request(http::verb method,
                          const std::string& host,
                          const std::string& port,
                          const std::string& target,
                          const std::string& body,
                          const RequestConfig& config) {

        // SSL 上下文
        ssl::context ctx{ssl::context::tlsv12_client};

        if (config.verify_ssl) {
            ctx.set_verify_mode(ssl::verify_peer);
            ctx.set_default_verify_paths();
        } else {
            ctx.set_verify_mode(ssl::verify_none);
        }

        // 解析器和流
        tcp::resolver resolver(ioc_);
        beast::ssl_stream<beast::tcp_stream> stream(ioc_, ctx);

        // 解析地址
        auto const results = resolver.resolve(host, port);

        // 连接
        beast::get_lowest_layer(stream).connect(results);

        // SSL 握手
        stream.handshake(ssl::stream_base::client);

        // 创建请求
        http::request<http::string_body> req{method, target, 11};
        req.set(http::field::host, host);
        req.set(http::field::user_agent, "HttpClient/1.0");

        // 设置请求头
        for (const auto& header : config.headers) {
            req.set(header.first, header.second);
        }

        // 设置请求体
        if (!body.empty()) {
            req.body() = body;
            req.prepare_payload();
        }

        // 发送请求
        http::write(stream, req);

        // 接收响应
        beast::flat_buffer buffer;
        http::response<http::dynamic_body> res;
        http::read(stream, buffer, res);

        // 优雅关闭
        beast::error_code ec;
        stream.shutdown(ec);
        if(ec == net::error::eof) {
            ec = {};
        }

        // 处理响应
        return parse_response(res);
    }

    Response parse_response(const http::response<http::dynamic_body>& res) {
        Response response;
        response.status_code = res.result_int();
        response.status_message = std::string(res.reason());
        response.body = beast::buffers_to_string(res.body().data());

        // 解析响应头
        for (const auto& field : res) {
            response.headers[std::string(field.name_string())] =
                std::string(field.value());
        }

        return response;
    }

    Response make_error_response(int code, const std::string& message) {
        Response response;
        response.status_code = code;
        response.body = message;
        return response;
    }
};

// 便捷的全局函数
namespace http_client {
    inline HttpClient::Response get(const std::string& url) {
        HttpClient client;
        return client.get(url);
    }

    inline HttpClient::Response post(const std::string& url,
                                    const std::string& data = "",
                                    const std::string& content_type = "application/json") {
        HttpClient client;
        return client.post(url, data, content_type);
    }

    inline HttpClient::Response put(const std::string& url,
                                   const std::string& data = "",
                                   const std::string& content_type = "application/json") {
        HttpClient client;
        return client.put(url, data, content_type);
    }

    inline HttpClient::Response del(const std::string& url) {
        HttpClient client;
        return client.del(url);
    }
}
